package com.safeneeds.sysmana.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.alibaba.fastjson.JSON;
import com.safeneeds.sysmana.entity.SysFunc;
import com.safeneeds.sysmana.entity.SysUserRole;
import com.safeneeds.sysmana.ser.ISysFuncService;
import com.safeneeds.sysmana.ser.impl.FuncRoleCacheService;
import com.safeneeds.util.base.RetType;
import com.safeneeds.util.base.UserInfoCache;
import com.safeneeds.util.date.DateUtil;
import com.safeneeds.util.log.ALogFactory;

/**
 * 系统拦截器，登录、权限校验
 * @author gaof
 * @date 2016年5月6日
 */
public class SecuFilter implements Filter {
	
	/* 运行模式(测试:false 上线:true) */
	private boolean runMode;
	/* 非法访问提示页面 */
	private String errorAccess;
	/* 非工作时间访问系统提示页面 */
	private String workOutPage;
	/* 系统每天暂停工作时间 */
	private String stopWorkTime;
	/* 系统每天开始工作时间 */
	private String beginWorkTime;
	/* 访问系统超时提示页面 */
	private String sessionOutPage;
	
	/* 请求类型 */
	/*网站端，需要登录、需要授权*/
	private final String WEB_LOGIN_AUTH = ".do";
	/*网站端，需要登录、不需要授权*/
	private final String WEB_LOGIN_NOAUTH = ".dol";
	/*网站端，不需要登录、不需要授权*/
	private final String WEB_NOLOGIN_NOAUTH = ".dop";
	/*接口端，需要登录、需要授权*/
	private final String INTER_LOGIN_AUTH = ".ido";
	/*接口端，需要登录、不需要授权*/
	private final String INTER_LOGIN_NOAUTH = ".idol";
	/*接口端，不需要登录、不需要授权*/
	private final String INTER_NOLOGIN_NOAUTH = ".idop";
	

	/**
	 * 初始化
	 * @param filterConfig
	 * @throws ServletException
	 */
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		
		String runModeFlag = filterConfig.getInitParameter("runMode");
		if ("false".equals(runModeFlag)) {
			runMode = false;
		}else{
			runMode = true;
		}
		workOutPage = filterConfig.getInitParameter("workOutPage");
		errorAccess = filterConfig.getInitParameter("errorAccess");
		stopWorkTime = filterConfig.getInitParameter("stopWorkTime");
		beginWorkTime = filterConfig.getInitParameter("beginWorkTime");
		sessionOutPage = filterConfig.getInitParameter("sessionOutPage");
	}
	
	/**
	 * 安全拦截校验
	 * @param request
	 * @param response
	 * @param chain
	 * @throws IOException
	 * @throws ServletException
	 */
	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;

		String visoUrl = req.getServletPath().substring(1);// 当前访问url标识符
		//ALogFactory.getLog().info(visoUrl);
		
		/*判断运行模式 false为开发模式，true为上线模式*/
		if (runMode) {
			
			/*判断请求类型并校验*/
			if(visoUrl.endsWith(WEB_NOLOGIN_NOAUTH)){//网站端，不需要登录、不需要授权
			
				boolean result = webCheckWorkTime(request, response, chain);//网站端校验工作时间
				if(!result){
					return;
				}
				
			}else if(visoUrl.endsWith(INTER_NOLOGIN_NOAUTH)){//接口端，不需要登录、不需要授权
				
				boolean result = interCheckWorkTime(request, response, chain);//接口端校验工作时间
				if(!result){
					return;
				}
				
			}else if(visoUrl.endsWith(WEB_LOGIN_NOAUTH)){//网站端，需要登录、不需要授权
				
				boolean result = true;
				result = webCheckWorkTime(request, response, chain);//网站端校验工作时间
				if(!result){
					return;
				}
				result = webCheckLogin(request, response, chain);//网站端校验登录
				if(!result){
					return;
				}
				
			}else if(visoUrl.endsWith(INTER_LOGIN_NOAUTH)){//接口端，需要登录、不需要授权
				
				boolean result = true;
				result = interCheckWorkTime(request, response, chain);//接口端校验工作时间
				if(!result){
					return;
				}
				result = interCheckLogin(request, response, chain);//接口端校验用户登录
				if(!result){
					return;
				}
				
			}else if(visoUrl.endsWith(WEB_LOGIN_AUTH)){//网站端，需要登录、需要授权
				
				boolean result = true;
				result = webCheckWorkTime(request, response, chain);//网站端校验工作时间
				if(!result){
					return;
				}
				result = webCheckLogin(request, response, chain);//网站端校验登录
				if(!result){
					return;
				}
				result = webCheckAuth(visoUrl, request, response, chain);//网站端校验权限
				if(!result){
					return;
				}
				
			}else if(visoUrl.endsWith(INTER_LOGIN_AUTH)){//接口端，需要登录、需要授权
				
				boolean result = true;
				result = interCheckWorkTime(request, response, chain);//接口端校验工作时间
				if(!result){
					return;
				}
				result = interCheckLogin(request, response, chain);//接口端校验用户登录
				if(!result){
					return;
				}
				result = interCheckAuth(visoUrl, request, response, chain);//接口端校验权限
				if(!result){
					return;
				}
				
			}
			
		}else{
			ALogFactory.getLog().info("运行于开发模式，默认已授权：" + visoUrl);
			chain.doFilter(request, response);// 公共资源
			
			return;
		}
		
		//校验通过，正常跳转
		chain.doFilter(request, response);
	}
	
	/**
	 * 接口端校验权限
	 * @param visoUrl
	 * @param request
	 * @param response
	 * @param chain
	 * @return 
	 * @throws IOException 
	 * @throws ServletException 
	 */
	private boolean interCheckAuth(String visoUrl, ServletRequest request,
			ServletResponse response, FilterChain chain) throws IOException, ServletException {
		
		ApplicationContext ac = WebApplicationContextUtils
				.getRequiredWebApplicationContext(((HttpServletRequest) request).getSession()
						.getServletContext());// spring容器
		FuncRoleCacheService funcRoleCache = (FuncRoleCacheService) ac
				.getBean("funcRoleCache");// 功能、岗位缓存器
		SysFunc func = funcRoleCache.getFuncByFuncUrl(visoUrl);
		
		/*功能不存在*/
		if(func == null){
			RetType reType = new RetType();
			reType.setErrCode(RetType.RET_FAILE);
			reType.setErrMsg("访问资源不存在");
			
			PrintWriter out = response.getWriter();
			out.print(JSON.toJSONString(reType));
			out.flush();
			out.close();
			
			return false;
		}
		
		/*公共访问资源*/
		if(ISysFuncService.FUNC_ACCE_TYPE_PUB.equals(func.getAcceType())){
			return true;
		}
		
		/*校验用户是否有权限*/
		boolean vistorAble = false;
		UserInfoCache useInfo = (UserInfoCache) ((HttpServletRequest) request).getSession().getAttribute(
						UserInfoCache.USER_INFO_SESSION_CACHE_KEY);// 用户信息
		
		List<SysUserRole> userRoles = useInfo.getUserRoles();//获取用户角色缓存
		if(userRoles == null || userRoles.isEmpty()){//没有岗位
			return false;
		}
		
		for (SysUserRole role : userRoles) {
			
			int roleId = role.getId().getRoleId();
			if(roleId == 0){
				continue;
			}
			
			vistorAble = funcRoleCache.checkVisoSec(func.getFuncId(), roleId);//校验权限
			if (vistorAble) {
				break;
			}
		}
		
		/*校验不通过*/
		if (!vistorAble) {
			RetType reType = new RetType();
			reType.setErrCode(RetType.RET_FAILE);
			reType.setErrMsg("没有访问该资源的权限");
			
			PrintWriter out = response.getWriter();
			out.print(JSON.toJSONString(reType));
			out.flush();
			out.close();
			
			return false;
		}
		
		return true;
	}

	/**
	 * 网站端校验权限
	 * @param visoUrl 
	 * @param request
	 * @param response
	 * @param chain
	 * @return 
	 * @throws IOException 
	 * @throws ServletException 
	 */
	private boolean webCheckAuth(String visoUrl, ServletRequest request, ServletResponse response,
			FilterChain chain) throws ServletException, IOException {
		
		ApplicationContext ac = WebApplicationContextUtils
				.getRequiredWebApplicationContext(((HttpServletRequest) request).getSession()
						.getServletContext());// spring容器
		FuncRoleCacheService funcRoleCache = (FuncRoleCacheService) ac
				.getBean("funcRoleCache");// 功能、岗位缓存器
		SysFunc func = funcRoleCache.getFuncByFuncUrl(visoUrl);
		
		/*功能不存在*/
		if(func == null){
			request.setAttribute("errorMessage", "访问资源[" + visoUrl
					+ "]不存在。");
			response.setContentType("text/html;charset=UTF-8");
			RequestDispatcher rd = null;
			rd = request.getRequestDispatcher(errorAccess);
			rd.forward(request, response);
			ALogFactory.getLog().info("访问资源[" + visoUrl + "]不存在。");
			
			return false;
		}
		
		/*公共访问资源*/
		if(ISysFuncService.FUNC_ACCE_TYPE_PUB.equals(func.getAcceType())){
			return true;
		}
		
		/*校验用户是否有权限*/
		boolean vistorAble = false;
		UserInfoCache useInfo = (UserInfoCache) ((HttpServletRequest) request).getSession().getAttribute(
						UserInfoCache.USER_INFO_SESSION_CACHE_KEY);// 用户信息
		
		List<SysUserRole> userRoles = useInfo.getUserRoles();//获取用户角色缓存
		if(userRoles == null || userRoles.isEmpty()){//没有岗位
			return false;
		}
		
		for (SysUserRole role : userRoles) {
			
			int roleId = role.getId().getRoleId();
			if(roleId == 0){
				continue;
			}
			
			vistorAble = funcRoleCache.checkVisoSec(func.getFuncId(), roleId);//校验权限
			if (vistorAble) {
				break;
			}
		}
		
		/*校验不通过*/
		if (!vistorAble) {
			request.setAttribute("errorMessage", "访问资源["
					+ visoUrl + "]未授权，请重新登录或联系管理员。");
			response.setContentType("text/html;charset=UTF-8");
			RequestDispatcher rd = null;
			rd = request.getRequestDispatcher(errorAccess);
			rd.forward(request, response);
			ALogFactory.getLog().info("访问资源[" + visoUrl+ "]未授权，请重新登录或联系管理员。");
			
			return false;
		}
		
		return true;
	}

	/**
	 * 接口端校验登录
	 * @param request
	 * @param response
	 * @param chain
	 * @return 
	 * @throws IOException 
	 */
	private boolean interCheckLogin(ServletRequest request,
			ServletResponse response, FilterChain chain) throws IOException {
		
		/* 判断用户缓存是否注销，已注销返回false，存在返回true */
		UserInfoCache userInfoCache = (UserInfoCache) ((HttpServletRequest) request).getSession()
				.getAttribute(UserInfoCache.USER_INFO_SESSION_CACHE_KEY);
		
		if(userInfoCache == null || userInfoCache.getUserInfo() == null){
			
			RetType reType = new RetType();
			reType.setErrCode(RetType.RET_NO_LOGIN);
			reType.setErrMsg("用户未登录");
			
			PrintWriter out = response.getWriter();
			out.print(JSON.toJSONString(reType));
			out.flush();
			out.close();
			
			return false;
		}
		
		return true;
	}

	/**
	 * 网站端校验登录
	 * @param request
	 * @param response
	 * @param chain
	 * @return 
	 * @throws IOException 
	 * @throws ServletException 
	 */
	private boolean webCheckLogin(ServletRequest request,
			ServletResponse response, FilterChain chain) throws ServletException, IOException {
		
		/* 判断用户缓存是否注销，已注销返回false，存在返回true */
		UserInfoCache userInfoCache = (UserInfoCache) ((HttpServletRequest) request).getSession()
				.getAttribute(UserInfoCache.USER_INFO_SESSION_CACHE_KEY);
		
		if(userInfoCache == null || userInfoCache.getUserInfo() == null){
			response.setContentType("text/html;charset=UTF-8");
			RequestDispatcher rd = null;
			rd = request.getRequestDispatcher(sessionOutPage);
			rd.forward(request, response);
			ALogFactory.getLog().info("系统基础框架-->登录会话超时");
			
			return false;
		}
		
		return true;
	}

	/**
	 * 接口端校验工作时间
	 * @param request
	 * @param response
	 * @param chain
	 * @return 
	 * @throws IOException 
	 */
	private boolean interCheckWorkTime(ServletRequest request,
			ServletResponse response, FilterChain chain) throws IOException {
		
		String currDateTime = DateUtil.getDateByHMS();// 当前系统时间
		
		if (0 <= currDateTime.compareTo(stopWorkTime)
				|| 0 >= currDateTime.compareTo(beginWorkTime)) {
			
			RetType reType = new RetType();
			reType.setErrCode(RetType.RET_FAILE);
			reType.setErrMsg("非工作时间访问");
			
			PrintWriter out = response.getWriter();
			out.print(JSON.toJSONString(reType));
			out.flush();
			out.close();
			
			return false;
		}
		
		return true;
	}

	/**
	 * 网站端校验工作时间
	 * @param request
	 * @param response
	 * @param chain
	 * @throws IOException 
	 * @throws ServletException 
	 */
	private boolean webCheckWorkTime(ServletRequest request, ServletResponse response,
			FilterChain chain) throws ServletException, IOException {
		
		String currDateTime = DateUtil.getDateByHMS();// 当前系统时间
		
		if (0 <= currDateTime.compareTo(stopWorkTime)
				|| 0 >= currDateTime.compareTo(beginWorkTime)) {
			request.setAttribute("stopWorkTime", stopWorkTime);
			request.setAttribute("beginWorkTime", beginWorkTime);
			response.setContentType("text/html;charset=UTF-8");
			RequestDispatcher rd = null;
			rd = request.getRequestDispatcher(workOutPage);
			rd.forward(request, response);// 非工作时间登录系统
			
			return false;
		}
		
		return true;
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
	}

}
